package com.hqd.ch03.v13.reader.xml.resolver;

import com.hqd.ch03.v13.io.support.ClassPathResource;
import com.hqd.ch03.v13.io.Resource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 读取本地xsd校验文件进行校验
 */
public class PluggableSchemaResolver implements EntityResolver {
    public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
    private final String schemaMappingsLocation;
    private volatile Map<String, String> schemaMappings;

    public PluggableSchemaResolver(String schemaMappingsLocation) {
        this.schemaMappingsLocation = schemaMappingsLocation;
    }

    public PluggableSchemaResolver() {
        this(DEFAULT_SCHEMA_MAPPINGS_LOCATION);
    }

    @Override
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (systemId != null) {
            String resourceLocation = getSchemaMappings().get(systemId);
            /**
             * systemId以https开头，且资源不存在，尝试以http的形式获取
             */
            if (resourceLocation == null && systemId.startsWith("https:")) {
                resourceLocation = getSchemaMappings().get("http:" + systemId.substring(6));
            }
            /**
             * 资源存在，则尝试加载
             */
            if (resourceLocation != null) {
                Resource resource = new ClassPathResource(resourceLocation);
                try {
                    InputSource source = new InputSource(resource.getInputStream());
                    source.setPublicId(publicId);
                    source.setSystemId(systemId);
                    return source;
                } catch (FileNotFoundException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }

        return null;
    }

    /**
     * 读取指定目录下的配置文件，缓存起来
     *
     * @return
     */
    private Map<String, String> getSchemaMappings() {
        Map<String, String> schemaMappings = this.schemaMappings;
        if (schemaMappings == null) {
            synchronized (this) {
                schemaMappings = this.schemaMappings;
                if (schemaMappings == null) {
                    try {
                        Properties mappings = new Properties();
                        mappings.load(this.getClass().getClassLoader().getResourceAsStream(schemaMappingsLocation));
                        Set<Object> objects = mappings.keySet();
                        schemaMappings = new ConcurrentHashMap<>(objects.size());
                        for (Object key : objects) {
                            String keyStr = key.toString();
                            String value = mappings.getProperty(keyStr);
                            schemaMappings.put(keyStr, value);
                        }
                        this.schemaMappings = schemaMappings;
                    } catch (IOException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        }
        return schemaMappings;
    }


}
